package com.jmga.ecogasfinder.utilities;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.util.Log;

import com.google.android.maps.GeoPoint;
import com.jmga.ecogasfinder.activities.maps.ECOGasStationFinderMapActivity;

public class Tools {
	public ECOGasStationFinderMapActivity mapActivity;
	private static Tools instance;
	
	private Tools() {
	}
	
	public static Tools getInstance() {
		if(instance == null) {
			instance = new Tools();
		}

		return instance;
	}
	
	public static double getMean(int[] values) {
		double result = 0.0;
		
		for(int value : values) {
			result += value;
		}
		
		return result/values.length;
	}
	
	 public static double getVariance(int[] values) {
         double mean = Tools.getMean(values);
         double temp = 0;
         
         for(int value : values) {
             temp += (mean - value)*(mean - value);
         }
         
         return temp/values.length;
     }

	 public static double getStandardDeviation(int[] values) {
         return Math.sqrt(getVariance(values));
     }

	
	public static Drawable getBitmapDrawableScaled(Drawable drawable) {
		Drawable result = null;
		if (drawable != null) {
			Bitmap bitmapOrg = ((BitmapDrawable) drawable).getBitmap();
			int width = bitmapOrg.getWidth();
			int height = bitmapOrg.getHeight();

			Matrix matrix = new Matrix();

			matrix.postScale(0.25f, 0.20f);
			Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0, width,
					height, matrix, true);
			result = new BitmapDrawable(resizedBitmap);
		}
		
		return result;
	}
	
	public static double getDistanceDriving(String gmapsFeed, GeoPoint geoPointA, GeoPoint geoPointB) {
		Location locationA = new Location("Selected Point");
		locationA.setLongitude(geoPointA.getLongitudeE6() / 1E6);
		locationA.setLatitude(geoPointA.getLatitudeE6() / 1E6);
		
		Location locationB = new Location("Selected Point");
		locationB.setLongitude(geoPointB.getLongitudeE6() / 1E6);
		locationB.setLatitude(geoPointB.getLatitudeE6() / 1E6);
		
		return getDistanceDriving(gmapsFeed, locationA, locationB);		
	}
	
	public static double getDistanceDriving(String gmapsFeed, Location locationA, Location locationB) {
		URL url;
		
		DecimalFormat df = new DecimalFormat();
        DecimalFormatSymbols symbols = new DecimalFormatSymbols();
        symbols.setDecimalSeparator(',');
        symbols.setGroupingSeparator(' ');
        df.setDecimalFormatSymbols(symbols);
        
		try {
			String origin, destination;

			origin = locationA.getLatitude() + ","
					+ locationA.getLongitude();
			destination = locationB.getLatitude() + ","
					+ locationB.getLongitude();
			url = new URL(gmapsFeed.concat("&origin=" + origin
					+ "&destination=" + destination));
			
			Log.d(getInstance().getClass().toString(), "" + url.toExternalForm());

			URLConnection connection;
			connection = url.openConnection();
			
			HttpURLConnection httpConnection = (HttpURLConnection) connection;
			int responseCode = httpConnection.getResponseCode();

			if (responseCode == HttpURLConnection.HTTP_OK) {
				InputSource inputXml = new InputSource(httpConnection.getInputStream());
				XPathFactory factory = XPathFactory.newInstance();
				XPath xpath = factory.newXPath();

				NodeList nodes = (NodeList) xpath.evaluate(
						"/DirectionsResponse/route/leg/distance/text",
						inputXml, XPathConstants.NODESET);
				
				Number distanceValue = 0;
				try {
					String[] distanceValueStringArray = null;
					if(nodes != null && nodes.item(0) != null && nodes.item(0).getTextContent() != null) {
						distanceValueStringArray = nodes.item(0).getTextContent().split("km");
					}
					if(distanceValueStringArray != null &&  distanceValueStringArray[0] != null) {
						distanceValue = df.parse(distanceValueStringArray[0].trim());
					}
				} catch (ParseException e) {
					distanceValue = 0;
					Log.d("Tools", "Exception caughted " + e.getLocalizedMessage());
				}
				
				return distanceValue.doubleValue();
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
		
		return 0d;
	}

	public ECOGasStationFinderMapActivity getMapActivity() {
		return mapActivity;
	}
	
	public void setMapActivity(ECOGasStationFinderMapActivity mapAct) {
		mapActivity = mapAct;
	}
	
	public static JSONObject getLocationInfo(String url) {

		HttpGet httpGet = new HttpGet(url);
		HttpClient client = new DefaultHttpClient();
		HttpResponse response;
		StringBuilder stringBuilder = new StringBuilder();

		try {
			response = client.execute(httpGet);
			HttpEntity entity = response.getEntity();
			InputStream stream = entity.getContent();
			int b;
			while ((b = stream.read()) != -1) {
				stringBuilder.append((char) b);
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		JSONObject jsonObject = new JSONObject();
		try {
			jsonObject = new JSONObject(stringBuilder.toString());
		} catch (JSONException e) {
			e.printStackTrace();
		}

		return jsonObject;
	}
	
	public static String getLocationLatLong(JSONObject jsonObject) throws Exception {
		Double lon = Double.valueOf(0);
		Double lat = Double.valueOf(0);

		try {

			lon = ((JSONArray)jsonObject.get("results")).getJSONObject(0)
				.getJSONObject("geometry").getJSONObject("location")
				.getDouble("lng");

			lat = ((JSONArray)jsonObject.get("results")).getJSONObject(0)
				.getJSONObject("geometry").getJSONObject("location")
				.getDouble("lat");

		} catch (JSONException e) {
			throw e;
		}

		return lat.toString() + "," + lon.toString();
	}
	
	public static String getLocationLocality(JSONObject jsonObject) {
		String result = null;

		try {
			JSONArray address_components = ((JSONArray)jsonObject.get("results")).getJSONObject(0).getJSONArray("address_components");
			for(int i=0; i < address_components.length();i++) {
				JSONObject addressItem = address_components.getJSONObject(i);
				if(addressItem.getJSONArray("types").toString().indexOf("administrative_area_level_2") != -1) {
					result = addressItem.getString("long_name");
					break;
				}
			}

		} catch (JSONException e) {
			e.printStackTrace();
		}

		return result;
	}
	
	public static int checkCoord(Integer reference, int value, boolean isMin) {
		if(reference == null) {
			return value;
		}
		
		int result = reference;
		if(isMin) {
			if(value < reference) {
				result = value;
			}
		} else {
			if(value > reference) {
				result = value;
			}
		}
		
		return result;
	}
}
